package com.android.corestat.service;

import java.io.File;
import java.io.IOException;
import java.util.List;

import android.app.ActivityManager;
import android.app.AlarmManager;
import android.app.PendingIntent;
import android.app.Service;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.net.ConnectivityManager;
import android.os.IBinder;
import android.os.SystemClock;
import android.util.Log;

import com.android.corestat.database.PackageDatabase;
import com.android.corestat.thread.SingleThreadExecutor;
import com.android.corestat.utils.CSLog;
import com.android.corestat.utils.CSPrefs;
import com.android.corestat.utils.SimUtil;
import com.android.corestat.utils.Utils;

public class WorkingService extends Service {

	private static String TAG = "cs-service";

	private final static String ELAPSED_TIME = "elapsed_time";
	private final static String SIM_ONLINE_TIME = "sim_online_time";
	private final static String ACTION_ONE_HOUR_EVENT = "action.one.hour.event";
	private final static int MAX_SERVICE_INQUERY_NUM = 256;
	// ONE_DAY THREE_DAY SIM_ONLINE_REQUEST 都是以秒为单位计算
	private final static int ONE_DAY = 60 * 60 * 24;
	private final static int THREE_DAY = 60 * 60 * 24 * 3;
	private final static int TWO_HOUR = 60 * 60 * 2;
	private final static long INTERVAL = 1000 * 60 * 5;

//	 private final static int ONE_DAY = 60 * 3;// 10 minutes
//	 private final static int THREE_DAY = 60 * 5;// 15 minutes
//	 private final static int TWO_HOUR = 60 * 2;// 2 minutes
//	 private final static long INTERVAL = 1000 * 10;// 10 second

	private static final int PACKAGE_FIRST = 1;
	private static final int PACKAGE_SECOND = 2;
	private static final int PACKAGE_THIRD = 3;
	private static final int PACKAGE_FOURTH = 4;
	private static final int PACKAGE_FIVE = 5;

	public static void startWorkingService(Context context, long delayTime) {
		CSLog.i(TAG, "startWorkingService");
		AlarmManager am = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
		Intent intent = new Intent(context, WorkingService.class);
		intent.setAction(ACTION_ONE_HOUR_EVENT);
		PendingIntent pi = PendingIntent.getService(context, 1, intent,
				PendingIntent.FLAG_UPDATE_CURRENT);
		am.setRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP, SystemClock.elapsedRealtime()
				+ delayTime, INTERVAL, pi);
	}

	private void closeWorkingService(Context context) {
		CSLog.i(TAG, "closeWorkingService");
		AlarmManager am = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
		Intent intent = new Intent(context, WorkingService.class);
		intent.setAction(ACTION_ONE_HOUR_EVENT);
		PendingIntent pi = PendingIntent.getService(context, 1, intent,
				PendingIntent.FLAG_UPDATE_CURRENT);
		am.cancel(pi);
		setCoreStatFinished(context, true);
		stopSelf();
	}

	public static boolean isServiceTaskFinished(Context context) {
		if (isCoreStatFinished(context)) {
			CSLog.d(TAG, "corestat finished");
			return true;
		}
		PackageDatabase db = PackageDatabase.newInstance(context);
		int unSent = (db.getUnsentsSeq() == null) ? 0 : db.getUnsentsSeq().size();

        return db.exist(PACKAGE_FIVE) && db.exist(PACKAGE_FOURTH) && db.exist(PACKAGE_THIRD)
                && db.exist(PACKAGE_SECOND) && db.exist(PACKAGE_FIRST) && unSent == 0;
    }

	public static boolean isServiceRunning(Context context) {
		boolean isRunning = false;
		ActivityManager activityManager = (ActivityManager) context
				.getSystemService(Context.ACTIVITY_SERVICE);
		List<ActivityManager.RunningServiceInfo> serviceList = activityManager
				.getRunningServices(MAX_SERVICE_INQUERY_NUM);
		if (serviceList == null || serviceList.size() == 0) {
			return false;
		}
		for (int i = 0; i < serviceList.size(); i++) {
			ComponentName cn = serviceList.get(i).service;
			if (cn != null) {
				if (WorkingService.class.getName().equals(cn.getClassName())
						&& context.getPackageName().equals(cn.getPackageName())) {
					isRunning = true;
					break;
				}
			}
		}
		return isRunning;
	}

	@Override
	public void onCreate() {
		super.onCreate();
		CSLog.i(TAG, "onCreate");
	}

	@Override
	public IBinder onBind(Intent intent) {
		return null;
	}

	@Override
	public int onStartCommand(Intent intent, int flags, int startId) {
		if (intent == null) {
			return super.onStartCommand(intent, flags, startId);
		}
//		CSLog.i(TAG, "onStartCommand:" + intent.getAction());
		if (ConnectivityManager.CONNECTIVITY_ACTION.equals(intent.getAction())) {
			handleNetChangeEvent(this);
		} else if (ACTION_ONE_HOUR_EVENT.equals(intent.getAction())) {
			handleOneHourEvent(this);
			if (Utils.isNetworkConnected(this)) {
				// 除了再网络切换的时候调用，在alarm中也调用，增加发送机会。
				handleNetChangeEvent(this); 
			}
		}

		return super.onStartCommand(intent, flags, startId);
	}

	private void handleNetChangeEvent(Context c) {

		SingleThreadExecutor executor = SingleThreadExecutor.getInstance();
		PackageDatabase db = PackageDatabase.newInstance(this);

		/* 1号包，首次检测到手机联网（不管wifi还是GPRS均可）后，将数据发回服务器 */
		if (!db.exist(PACKAGE_FIRST)) {
			CSLog.e("CoreState", "handleNetChangeEvent write first");
			executor.startWriteThread(this, PACKAGE_FIRST);
		}

		/* 2号包，首次检测到手机使用GPRS联网后，将数据包发回 */
		if (Utils.isGprs(c)) {
			if (!db.exist(PACKAGE_SECOND)) {
				CSLog.e("CoreState", "handleNetChangeEvent write second..");
				executor.startWriteThread(this, PACKAGE_SECOND);
			}
		}

		// 3号包，检测到手机插入SIM卡累计到达两个小时后，将数据发回。
		if (readSimOnlineTime() > TWO_HOUR) {
			if (!db.exist(PACKAGE_THIRD)) {
				executor.startWriteThread(this, PACKAGE_THIRD);
			}
		}

		// 4号包，检测到手机插入SIM卡累计到达24小时后，将数据发回
		if (readSimOnlineTime() > ONE_DAY) {
			if (!db.exist(PACKAGE_FOURTH)) {
				executor.startWriteThread(this, PACKAGE_FOURTH);
			}
		}

		// 5号包，检测到手机累计开机到达72小时，则将数据发回。
		if (readElapsedTime() > THREE_DAY) {
			if (!db.exist(PACKAGE_FIVE)) {
				executor.startWriteThread(this, PACKAGE_FIVE);
			}
		}

		executor.startSendThread(this);
	}

	private void handleOneHourEvent(Context ctx) {

		// 两次执行时间间隔
		int interval = elapsedTime(ctx);

		// 开机时间
		int elapseTime = readElapsedTime() + interval;
		writeElapsedTime(elapseTime);

		// 统计SIM卡在线时间
		if (SimUtil.isSimIn(this) && CSPrefs.getSimState(this)) {
			long simOnlineTime = readSimOnlineTime() + interval;
			writeSimOnlineTime(simOnlineTime);

		}

		saveSimStateAndTime();

		if (isServiceTaskFinished(ctx)) {
			closeWorkingService(ctx);
		}
	}

	private void saveSimStateAndTime() {
		CSPrefs.setSimState(this, SimUtil.isSimIn(this));
		CSPrefs.setElapsedRealTime(this, SystemClock.elapsedRealtime());
	}

	private int elapsedTime(Context c) {
		long compareTime = CSPrefs.getElapsedRealTime(c);
		long currentTime = SystemClock.elapsedRealtime();
		int interval = (int) (currentTime - compareTime) / 1000;
		if (interval <= 0) {
			interval = 0;
		}
		return interval;
	}

	private int readElapsedTime() {
		SharedPreferences sp = getSharedPreferences(ELAPSED_TIME, MODE_PRIVATE);
		return sp.getInt(ELAPSED_TIME, 0);
	}

	private void writeElapsedTime(int hours) {
		SharedPreferences sp = getSharedPreferences(ELAPSED_TIME, MODE_PRIVATE);
		Editor edit = sp.edit();
		edit.putInt(ELAPSED_TIME, hours);
		edit.commit();
	}

	private long readSimOnlineTime() {
		SharedPreferences sp = getSharedPreferences(SIM_ONLINE_TIME, MODE_PRIVATE);
		return sp.getLong(SIM_ONLINE_TIME, 0);
	}

	private void writeSimOnlineTime(long count) {
		SharedPreferences sp = getSharedPreferences(SIM_ONLINE_TIME, MODE_PRIVATE);
		Editor edit = sp.edit();
		edit.putLong(SIM_ONLINE_TIME, count);
		edit.commit();
	}

	private static final String STAT_FLAG_FILE = ".stat_finished";

	private static boolean isCoreStatFinished(Context context) {
		if (context == null) {
			return false;
		}
		File dir = context.getExternalFilesDir(null);
		if (dir == null) {
			return false;
		}
		if (!dir.exists()) {
			dir.mkdirs();
		}
		return new File(dir, STAT_FLAG_FILE).exists();
	}

	private static boolean setCoreStatFinished(Context context, boolean finish) {
		if (context == null) {
			return false;
		}

		File dir = context.getExternalFilesDir(null);
		if (dir == null) {
			return false;
		}

		File file = new File(dir, STAT_FLAG_FILE);
		if (finish) {
			try {
				file.createNewFile();
			} catch (IOException e) {
				Log.d(TAG, "create file faied:" + e);
				return false;
			}
		} else {
			file.delete();
		}
		return true;
	}
}
